package com.share.device.emqx.handler.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.share.common.core.constant.DeviceConstants;
import com.share.common.core.utils.StringUtils;
import com.share.device.domain.Cabinet;
import com.share.device.domain.CabinetSlot;
import com.share.device.domain.PowerBank;
import com.share.device.emqx.annotation.GuiguEmqx;
import com.share.device.emqx.constant.EmqxConstants;
import com.share.device.emqx.handler.MassageHandler;
import com.share.device.service.ICabinetService;
import com.share.device.service.ICabinetSlotService;
import com.share.device.service.IPowerBankService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author YC
 */
@Slf4j
@Component
@GuiguEmqx(topic = EmqxConstants.TOPIC_PROPERTY_POST)
public class PropertyPostHandler implements MassageHandler {

    @Autowired
    private ICabinetService cabinetService;
    @Autowired
    private IPowerBankService powerBankService;
    @Autowired
    private ICabinetSlotService cabinetSlotService;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 接收属性上报消息（MQTT协议）
     *
     * @param message 订阅MQTT发来的消息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void handleMessage(JSONObject message) {
        log.info("handleMessage: {}", message.toJSONString());
        //消息编号
        String messageNo = message.getString("mNo");
        //防止重复请求
        String key = "property:post:" + messageNo;
        boolean isExist = redisTemplate.opsForValue().setIfAbsent(key, messageNo, 1, TimeUnit.HOURS);
        if (!isExist) {
            log.info("重复请求: {}", message.toJSONString());
            return;
        }
        // 从MQTT消息中获取 柜机编号、充电宝编号、插槽编号、当前电量
        String cabinetNo = message.getString("cNo");
        String powerBankNo = message.getString("pNo");
        String slotNo = message.getString("sNo");
        BigDecimal electricity = message.getBigDecimal("ety");
        // 验证参数非空
        if (StringUtils.isEmpty(cabinetNo)
                || StringUtils.isEmpty(powerBankNo)
                || StringUtils.isEmpty(slotNo)
                || null == electricity) {
            log.info("有参数为空: {}", message.toJSONString());
            return;
        }
        // 根据获取的参数查询 柜机Bean、充电宝Bean
        Cabinet cabinet = cabinetService.getBtCabinetNo(cabinetNo);
        // 获取充电宝
        PowerBank powerBank = powerBankService.getByPowerBankNo(powerBankNo);
        // 更新充电宝Bean 电量、状态（数据库设计 状态：0未投放 1可用 2已租用 3充电中 4故障）
        powerBank.setElectricity(electricity);
        // 电量大于最低可借用值
        if (electricity.subtract(DeviceConstants.ELECTRICITY_MIN).doubleValue() > 0) {
            powerBank.setStatus("1");
        } else {
            powerBank.setStatus("3");
        }
        powerBankService.updateById(powerBank);
        // 更新柜机Bean 可用充电宝数量
        List<CabinetSlot> cabinetSlotList = cabinetSlotService.list(
                new LambdaQueryWrapper<CabinetSlot>()
                        .eq(CabinetSlot::getStatus, "1")
                        .eq(CabinetSlot::getCabinetId, cabinet.getId())
                        .select(CabinetSlot::getPowerBankId)
        );
        List<Long> powerBankIdList = cabinetSlotList.stream().map(CabinetSlot::getPowerBankId).collect(Collectors.toList());
        long availableNum = powerBankService.count(
                new LambdaQueryWrapper<PowerBank>()
                        .in(PowerBank::getId, powerBankIdList)
                        .eq(PowerBank::getStatus, "1")
        );
        cabinet.setAvailableNum((int) availableNum);
        cabinet.setUpdateTime(new Date());
        cabinetService.updateById(cabinet);
    }

}

